﻿    using System;
	using System.Collections;
    using System.Collections.Generic;
	using System.Collections.Specialized;
	using System.Linq;


namespace DailyFx.UI
{

	public abstract class UIConductor<T> : UIControl, IUIConductor<T>
		where T : class
	{
		/// <summary>
		///		Contains all children .
		/// </summary>
		protected readonly BindableCollection<T> _children = new BindableCollection<T>();
		
		
		/// <summary>
		/// 
		/// </summary>
		IClosePolicy<T> _closePolicy;

		/// <summary>
		/// 
		/// </summary>
		readonly bool _openPublicChildren;


		/// <summary>
		///		c'tor
		/// </summary>
		public UIConductor( bool openPublicChildren )
		{
			this._children.CollectionChanged += (s, e) =>
			{
				switch (e.Action)
				{
					case NotifyCollectionChangedAction.Add:
						e.NewItems.OfType<IUIChild>().Apply(x => x.Parent = this);
						break;
					case NotifyCollectionChangedAction.Remove:
						e.OldItems.OfType<IUIChild>().Apply(x => x.Parent = null);
						break;
					case NotifyCollectionChangedAction.Replace:
						e.NewItems.OfType<IUIChild>().Apply(x => x.Parent = this);
						e.OldItems.OfType<IUIChild>().Apply(x => x.Parent = null);
						break;
					case NotifyCollectionChangedAction.Reset:
						this._children.OfType<IUIChild>().Apply(x => x.Parent = this);
						break;
				}
			};

			this._openPublicChildren = openPublicChildren;

		}


		/// <summary>
		///		Gets or sets the close policy .
		/// </summary>
		public IClosePolicy<T> ClosePolicy
		{
			get { return this._closePolicy ?? (this._closePolicy = new DefaultClosePolicy<T>() ); }
			set { _closePolicy = value; }
		}

		/// <summary>
		///		Enables the specified child.
		/// </summary>
		public virtual void EnableChild ( T child )
		{
			if (child == null)
				return;

			child = EnsureChild (child);

			if ( this.IsEnabled )
			{
				UIControlExtension.TryEnableChild (child);
			}

			this.OnChildRequireEnabled (child, true);
		}

		/// <summary>
		///		Disables the specified child.
		/// </summary>
		public virtual void DisableChild ( T child, bool close)
		{
			if (child == null)
			{
				return;
			}

			if (close)
			{
				this.ClosePolicy.Apply (new[] { child }, (canClose, closable) =>
				{
					if ( canClose )
						CloseChildImpl(child);
				});
			}
			else
			{
				UIControlExtension.TryDisableChild ( child, false);
			}
		}


		void IUIConductor.EnableChild ( object child )
		{
			this.EnableChild ( (T)child );
		}

		void IUIConductor.DisableChild ( object child, bool close )
		{
			this.DisableChild ( (T)child, close );
		}

		/// <summary>
		///		Gets all the children that are currently being conducted.
		/// </summary>
		public IBindableCollection<T> Children
		{
			get { return this._children; }
		}

		/// <summary>
		///		Gets the children.
		/// </summary>
		public IEnumerable<T> GetChildren()
		{
			return this._children;
		}

		/// <summary>
		/// 
		/// </summary>
		IEnumerable IUIParent.GetChildren ()
		{
			return this.GetChildren();
		}

		/// <summary>
		///		Ensures that an child is ready to be enabled .
		/// </summary>
		protected virtual T EnsureChild ( T newChild )
		{
			var index = this._children.IndexOf( newChild );

			if (index == -1)
			{
				this._children.Add( newChild);
			}
			else
			{
				newChild = this._children[index];
			}

			var c = newChild as IUIChild ;
			if ( c != null && c.Parent != this )
				c.Parent = this;

			return newChild;
		}


		protected virtual void CloseChildImpl ( T child )
		{
			UIControlExtension.TryDisableChild ( child, true);
			this._children.Remove ( child );
		}


		/// <summary>
		///		Occurs when an enabling request is processed.
		/// </summary>
		public event EventHandler<UIEnabledNotifyEventArgs> ChildRequireEnabled = delegate { };

		
		/// <summary>
		///		Called by a subclass when an enabling needs processing.
		/// </summary>
		protected virtual void OnChildRequireEnabled ( T child, bool success )
		{
			if ( child == null )
			{
				return;
			}

			this.ChildRequireEnabled ( this, 
				new UIEnabledNotifyEventArgs { UIElement = child, IsSucceed = success });
		}


		/// <summary>
		///		Called when enabling this conductor .
		/// </summary>
		protected override void OnEnabled ()
		{
			this._children.OfType<IUIStatus>().Apply(x => x.SetEnabled());
		}

		/// <summary>
		///		Called when disabling the conductor .
		/// </summary>
		protected override void OnDisabled ( bool close )
		{
			this._children.OfType<IUIStatus>().Apply(x => x.SetDisabled(close));
			if ( close )
			{
				this._children.Clear();
			}
		}

		
		/// <summary>
		///		Called to check whether or not this conductor can closed .
		/// </summary>
		public override void CanClose ( Action<bool> callback )
		{
			this.ClosePolicy.Apply( this._children, (canClose, closable) =>
			{
				if ( !canClose && closable.Any() )
				{
					closable.OfType<IUIStatus>().Apply(x => x.SetDisabled(true));
					this._children.RemoveRange ( closable );
				}

				callback( canClose ) ;
			});
		}


          /// <summary>
          ///	Called when loading .
          /// </summary>
          protected override void OnLoaded ()
          {
              if ( this._openPublicChildren )
              {
  #if WinRT                
				  this.GetType().GetRuntimeProperties()
								.Where( x => x.Name != "Parent" 
										&& typeof(T).GetTypeInfo().IsAssignableFrom(x.PropertyType.GetTypeInfo()) )
								.Select(x => x.GetValue(this, null))
								.Cast<T>()
								.Apply( this.EnableChild );
#else
				  this.GetType().GetProperties()
								.Where(x => x.Name != "Parent" && typeof(T).IsAssignableFrom(x.PropertyType))
								.Select(x => x.GetValue(this, null))
								.Cast<T>()
								.Apply( this.EnableChild );
#endif
			  }
          }


	}
   
}